package com.cx.config;

import com.cx.async.AsyncRedis;
import com.cx.codec.SerializedObjectCodec;
import com.cx.property.LettuceProperties;
import com.cx.reactive.ReactiveRedis;
import com.cx.support.AsyncCallback;
import com.cx.utils.CacheConsts;
import com.cx.utils.SerializeAdapter;
import io.lettuce.core.codec.CompressionCodec;
import io.lettuce.core.codec.RedisCodec;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;

/**
 * Created on 2019-04-18 15:42.
 * @author 舒建辉
 */
public class LettuceRedisAdapter {

    private final AsyncRedis asyncRedis;

    private final ReactiveRedis reactiveRedis;

    private static LettuceProperties lettuceProperties = SerializeAdapter.lettuceProperties();

    public LettuceRedisAdapter(AsyncRedis asyncRedis, ReactiveRedis reactiveRedis) {
        this.asyncRedis = asyncRedis;
        this.reactiveRedis = reactiveRedis;
    }

    public static RedisCodec<String, Object> objectGZIPCodec(){
        return CompressionCodec.valueCompressor(new SerializedObjectCodec(), CompressionCodec.CompressionType.GZIP);
    }

    /*********************************** String ***********************************/

    /**
     * 单个异步执行keys
     *
     */
    public List<String> keys(final String key) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.keys(key);
            default: return asyncRedis.keys(key);
        }
    }

    /**
     * 单个异步执行exists
     *
     */
    public Boolean exists(final String key) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.exists(key);
            default: return asyncRedis.exists(key);
        }
    }

    /**
     * 单个异步执行del
     * @param keys
     */
    public void del(final String... keys) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.del(keys); break;
            default: asyncRedis.del(keys);
        }
    }

    /**
     * 单个异步执行set
     *
     */
    public void set(final String key, final Object val) {
        set(key, val, lettuceProperties.getCacheLevel2Ttl());
    }

    /**
     * 单个异步执行set
     *
     */
    public void set(final String key, final Object val, final Long expireTime) {
        if(ObjectUtils.isEmpty(val)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.set(key, val, expireTime); break;
            default: asyncRedis.set(key, val, expireTime);
        }
    }

    /**
     * 单个异步执行setlist
     *
     */
    public <T> void setlist(final String key, final List<T> list) {
        setlist(key, list, lettuceProperties.getCacheLevel2Ttl());
    }

    /**
     * 单个异步执行setlist
     *
     */
    public <T> void setlist(final String key, final List<T> list, final Long expireTime) {
        if(CollectionUtils.isEmpty(list)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.setlist(key, list, expireTime); break;
            default: asyncRedis.setlist(key, list, expireTime);
        }
    }

    /**
     * 单个异步执行setex
     *
     */
    public void setex(final String key, final Object obj) {
        setex(key, obj, lettuceProperties.getCacheLevel2Ttl());
    }

    /**
     * 单个异步执行setex
     *
     */
    public void setex(final String key, final Object obj, final long expireTime) {
        if(ObjectUtils.isEmpty(obj)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.setex(key, obj, expireTime); break;
            default: asyncRedis.setex(key, obj, expireTime);
        }
    }

    /**
     * 单个异步执行setexlist
     *
     */
    public <T> void setexlist(final String key, final List<T> list) {
        setexlist(key, list, lettuceProperties.getCacheLevel2Ttl());
    }

    /**
     * 单个异步执行setexlist
     *
     */
    public <T> void setexlist(final String key, final List<T> list, final long expireTime) {
        if(CollectionUtils.isEmpty(list)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.setexlist(key, list, expireTime); break;
            default: asyncRedis.setexlist(key, list, expireTime);
        }
    }

    /**
     * 单个异步执行setnx
     *
     */
    public void setnx(final String key, final Object obj) {
        if(ObjectUtils.isEmpty(obj)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.setnx(key, obj); break;
            default: asyncRedis.setnx(key, obj);
        }
    }

    /**
     * 单个异步执行setnxlist
     *
     */
    public <T> void setnxlist(final String key, final List<T> list) {
        if(CollectionUtils.isEmpty(list)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.setnxlist(key, list); break;
            default: asyncRedis.setnxlist(key, list);
        }
    }

    /**
     * 单个异步执行get
     *
     */
    public <T> T get(final String key, final Class<T> targetClass) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.get(key, targetClass);
            default: return asyncRedis.get(key, targetClass);
        }
    }

    /**
     * 单个异步执行getlist
     *
     */
    public <T> List<T> getlist(final String key, final Class<T> targetClass) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.getlist(key, targetClass);
            default: return asyncRedis.getlist(key, targetClass);
        }
    }

    /**
     * 批量异步执行mset
     *
     */
    public void mset(final Map<String, Object> objectMap) {
        if(CollectionUtils.isEmpty(objectMap)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.mset(objectMap); break;
            default: asyncRedis.mset(objectMap);
        }
    }

    /**
     * 批量异步执行setex
     *
     */
    public void batchSetex(final Map<String, Object> objectMap) {
        batchSetex(objectMap, lettuceProperties.getCacheLevel2Ttl());
    }

    /**
     * 批量异步执行setex
     *
     */
    public void batchSetex(final Map<String, Object> objectMap, final long expireTime) {
        if(CollectionUtils.isEmpty(objectMap)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.batchSetex(objectMap, expireTime); break;
            default: asyncRedis.batchSetex(objectMap, expireTime);
        }
    }

    /**
     * 批量异步执行mget
     *
     */
    public <T> Map<String, T> mget(final List<String> keys, final Class<T> targetClass) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.mget(keys, targetClass);
            default: return asyncRedis.mget(keys, targetClass);
        }
    }

    /**
     * 批量异步执行get
     *
     */
    public <T> List<T> batchGet(final List<String> keys, final Class<T> targetClass) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.batchGet(keys, targetClass);
            default: return asyncRedis.batchGet(keys, targetClass);
        }
    }

    /*********************************** Hash ***********************************/

    /**
     * 单个异步执行hdel
     *
     */
    public void hdel(final String key, final String... keys) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.hdel(key, keys); break;
            default: asyncRedis.hdel(key, keys);
        }
    }

    /**
     * 单个异步执行hmset
     *
     */
    public void hmset(final String key, final Map<String, Object> entityMap) {
        if(CollectionUtils.isEmpty(entityMap)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.hmset(key, entityMap); break;
            default: asyncRedis.hmset(key, entityMap);
        }
    }

    /**
     * 单个异步执行hgetall
     *
     */
    public Map<String, Object> hgetall(final String key) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.hgetall(key);
            default: return asyncRedis.hgetall(key);
        }
    }

    /**
     * 批量异步执行hmset
     *
     */
    public void batchHmset(final Map<String, Map<String, Object>> map) {
        if(CollectionUtils.isEmpty(map)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.batchHmset(map); break;
            default: asyncRedis.batchHmset(map);
        }
    }

    /**
     * 批量异步执行hgetall
     *
     */
    public List<Map<String, Object>> batchHgetall(final List<String> keys) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.batchHgetall(keys);
            default: return asyncRedis.batchHgetall(keys);
        }
    }

    /*********************************** List ***********************************/

    /**
     * 异步执行lpush
     *
     */
    public void lpush(final String key, final List<String> list) {
        if(CollectionUtils.isEmpty(list)){
            return;
        }

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.lpush(key, list); break;
            default: asyncRedis.lpush(key, list);
        }
    }

    /**
     * 异步执行lrange
     *
     */
    public List<Object> lrange(final String key) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.lrange(key);
            default: return asyncRedis.lrange(key);
        }
    }

    /*********************************** Set ***********************************/

    /**
     * 异步执行smembers
     *
     */
    public List<Object> smembers(final String key) {
        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : return reactiveRedis.smembers(key);
            default: return asyncRedis.smembers(key);
        }
    }

    /*********************************** 通用 ***********************************/
    /**
     * 多执行多个异步命令
     * 参数说明：其中一个可为空
     */
    public void batchProcessAsync(final AsyncCallback asyncCallback) {

        switch (lettuceProperties.getCacheMode()){
            case CacheConsts.REACTIVE_PIPELINE :
            case CacheConsts.REACTIVE : reactiveRedis.batchProcess(asyncCallback); break;
            default: asyncRedis.batchProcess(asyncCallback);
        }
    }
}